require 'zpack'
local zunpack=zunpack
local zpack=zpack
local floor=math.floor
local type,pairs=type,pairs

module(..., package.seeall)

local _readvar,_readtable,_readtypeval

function ReadTable(buf,pos)
	local tv={}
	local cnt
	pos,cnt=zunpack(buf,'e',pos)
	local k,v
	for i=1,cnt do
		pos,k=_readvar(buf,pos)
		pos,v=_readvar(buf,pos)
		tv[k]=v
	end
	return pos,tv
end
_readtable=ReadTable
function ReadTypeVal(ty,buf,pos)
	local v
	if ty==1 then
		v=nil 
	else
		if ty==4 then pos,v=zunpack(buf,'E',pos) --asn int32
		elseif ty==5 then pos,v=zunpack(buf,'n',pos) -- lua number
		elseif ty==2 then v=false
		elseif ty==3 then v=true
		elseif ty==0x11 then pos,v=zunpack(buf,'j',pos)
		elseif ty==0x12 then pos,v=_readtable(buf,pos)
		else
			error('unknow var type ' .. ty)
		end
		assert(v~=nil,'decode error')
	end
	return pos,v
end
_readtypeval=ReadTypeVal
function ReadVar(buf,pos)
	local ty,v
	pos,ty=zunpack(buf,'b',pos)
	assert(ty)
	return _readtypeval(ty,buf,pos)
end
_readvar=ReadVar

function ToType(v)
	local ty=type(v)
	if ty=='nil' then return 1 
	elseif ty=='string' then return 0x11
	elseif ty=='table' then return 0x12
	elseif ty=='boolean' then return (v and 3) or 2
	elseif ty=='number' then
		local i=floor(v)
		if i==v and i>=-2147483648 and i<=2147483647 then
			return 4
		else
			return 5
		end
	else
		error('unsupport type ' .. ty)
	end
end
local _totype=ToType
local _writevar,_writetable,_writetypeval
function WriteTable(t)
	local cnt,buf=0,''
	if t then
		for k,v in pairs(t) do
			cnt=cnt+1
			buf=buf .. _writevar(k) .. _writevar(v)
		end
	end
	return zpack('e',cnt) .. buf
end
_writetable=WriteTable

function WriteTypeVal(ty,v)
	if ty==1 then
		return ''
	else
		if ty==4 then return zpack('E',v)
		elseif ty==5 then return zpack('n',v)
		elseif ty==2 then return ''
		elseif ty==3 then return ''
		elseif ty==0x11 then return zpack('j',v)
		elseif ty==0x12 then return WriteTable(v)
		else
			error('unknow var type ' .. ty)
		end
		assert(v,'decode error')
	end
end
_writetypeval=WriteTypeVal
function WriteVar(v)
	local ty=_totype(v)
	return zpack('b',ty) .. _writetypeval(ty,v)
end
_writevar=WriteVar
